﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

namespace ContainerPerformance
{
    class Program
    {
        static string[] stringData;
        static string[] stringOnBeginData;
        static string[] stringOnEndData;
        static Guid[] guidData;
        static int[] intData;
        static byte[][] byteData;
        static CustomKey[] customData;
        static void Main(string[] args)
        {
            Console.WriteLine("Prepare Performance Tests");
            Console.WriteLine("  Stopwatch Resolution (nS): " + (1000000000.0 / Stopwatch.Frequency).ToString());

            InitData(1000000);

            Dictionary<string, int> stringDictionary = new Dictionary<string, int>();
            Dictionary<string, int> stringOnBeginDictionary = new Dictionary<string, int>();
            Dictionary<string, int> stringOnEndDictionary = new Dictionary<string, int>();
            Dictionary<int, int> intDictionary = new Dictionary<int, int>();
            Dictionary<Guid, int> guidDictionary = new Dictionary<Guid, int>();
            Dictionary<byte[], int> byteDictionary = new Dictionary<byte[], int>();
            Dictionary<CustomKey, int> customDictionary = new Dictionary<CustomKey, int>();
            Dictionary<CustomKey, int> customDictionaryWithComparer = new Dictionary<CustomKey, int>(new CustomKeyComparer());

            Stopwatch watch = new Stopwatch();

            Console.WriteLine();
            Console.WriteLine("  Fill String Dictionary");
            watch.Reset();
            watch.Start();
            for (int i = 0; i < stringData.Length; ++i)
            {
                stringDictionary.Add(stringData[i], i);
            }
            watch.Stop();
            Console.WriteLine("  Fill String Dictionary Elapsed Time: " + ((double)watch.ElapsedTicks / Stopwatch.Frequency * 1000).ToString());

            GC.Collect();
            Console.WriteLine("  Search String Dictionary");
            watch.Start();
            for (int i = 0; i < stringData.Length; ++i)
            {
                
                int result = stringDictionary[stringData[i]];
                if (result != i)
                    throw new InvalidOperationException();

            }
            watch.Stop();
            Console.WriteLine("  Search String Dictionary String Dictioanry Elapsed Time: " + ((double)watch.ElapsedTicks / Stopwatch.Frequency * 1000).ToString());
            stringDictionary = null;


            GC.Collect();
            Console.WriteLine();
            Console.WriteLine("  Fill String On Begin Dictionary");
            watch.Reset();
            watch.Start();
            for (int i = 0; i < stringOnBeginData.Length; ++i)
            {
                stringOnBeginDictionary.Add(stringOnBeginData[i], i);
            }
            watch.Stop();
            Console.WriteLine("  Fill String On Begin Dictionary Elapsed Time: " + ((double)watch.ElapsedTicks / Stopwatch.Frequency * 1000).ToString());

            GC.Collect();
            Console.WriteLine("  Search String On Begin Dictionary");
            watch.Start();
            for (int i = 0; i < stringOnBeginData.Length; ++i)
            {

                int result = stringOnBeginDictionary[stringOnBeginData[i]];
                if (result != i)
                    throw new InvalidOperationException();

            }
            watch.Stop();
            Console.WriteLine("  Search String On Begin Dictionary String Dictioanry Elapsed Time: " + ((double)watch.ElapsedTicks / Stopwatch.Frequency * 1000).ToString());
            stringOnBeginDictionary = null;

            GC.Collect();
            Console.WriteLine();
            Console.WriteLine("  Fill String On End Dictionary");
            watch.Reset();
            watch.Start();
            for (int i = 0; i < stringOnEndData.Length; ++i)
            {
                stringOnEndDictionary.Add(stringOnEndData[i], i);
            }
            watch.Stop();
            Console.WriteLine("  Fill String On End Dictionary Elapsed Time: " + ((double)watch.ElapsedTicks / Stopwatch.Frequency * 1000).ToString());

            GC.Collect();
            Console.WriteLine("  Search String On End Dictionary");
            watch.Start();
            for (int i = 0; i < stringOnEndData.Length; ++i)
            {

                int result = stringOnEndDictionary[stringOnEndData[i]];
                if (result != i)
                    throw new InvalidOperationException();

            }
            watch.Stop();
            Console.WriteLine("  Search String On End Dictionary String Dictioanry Elapsed Time: " + ((double)watch.ElapsedTicks / Stopwatch.Frequency * 1000).ToString());
            stringOnEndDictionary = null;


            GC.Collect();
            Console.WriteLine();
            Console.WriteLine(" Fill Int Dictionary");
            watch.Reset();
            watch.Start();
            for (int i = 0; i < intData.Length; ++i)
            {
                intDictionary.Add(intData[i], i);
            }
            watch.Stop();
            Console.WriteLine("  Fill Int Dictionary Elapsed Time: " + ((double)watch.ElapsedTicks / Stopwatch.Frequency * 1000).ToString());

            GC.Collect();
            Console.WriteLine("  Search Int Dictionary");
            watch.Start();
            for (int i = 0; i < intData.Length; ++i)
            {

                int result = intDictionary[intData[i]];
                if (result != i)
                    throw new InvalidOperationException();

            }
            watch.Stop();
            Console.WriteLine("  Search Int Dictionary  Elapsed Time: " + ((double)watch.ElapsedTicks / Stopwatch.Frequency * 1000).ToString());
            intDictionary = null;

            GC.Collect();
            Console.WriteLine();
            Console.WriteLine(" Fill Guid Dictionary");
            watch.Reset();
            watch.Start();
            for (int i = 0; i < guidData.Length; ++i)
            {
                guidDictionary.Add(guidData[i], i);
            }
            watch.Stop();
            Console.WriteLine("  Fill Guid Dictionary Elapsed Time: " + ((double)watch.ElapsedTicks / Stopwatch.Frequency * 1000).ToString());

            GC.Collect();
            Console.WriteLine("  Search Guid Dictionary");
            watch.Start();
            for (int i = 0; i < guidData.Length; ++i)
            {

                int result = guidDictionary[guidData[i]];
                if (result != i)
                    throw new InvalidOperationException();

            }
            watch.Stop();
            Console.WriteLine("  Search Guid Dictionary  Elapsed Time: " + ((double)watch.ElapsedTicks / Stopwatch.Frequency * 1000).ToString());
            intDictionary = null;


            GC.Collect();
            Console.WriteLine();
            Console.WriteLine(" Fill Byte Dictionary");
            watch.Reset();
            watch.Start();
            for (int i = 0; i < byteData.GetLength(0); ++i)
            {
                byteDictionary.Add(byteData[i], i);
            }
            watch.Stop();
            Console.WriteLine("  Fill Byte Dictionary Elapsed Time: " + ((double)watch.ElapsedTicks / Stopwatch.Frequency * 1000).ToString());

            GC.Collect();
            Console.WriteLine("  Search Byte Dictionary");
            watch.Start();
            for (int i = 0; i < byteData.Length; ++i)
            {

                int result = byteDictionary[byteData[i]];
                if (result != i)
                    throw new InvalidOperationException();

            }
            watch.Stop();
            Console.WriteLine("  Search Byte Dictionary Elapsed Time: " + ((double)watch.ElapsedTicks / Stopwatch.Frequency * 1000).ToString());
            byteDictionary = null;

            GC.Collect();
            Console.WriteLine();
            Console.WriteLine(" Fill CustomKey Dictionary");
            watch.Reset();
            watch.Start();
            for (int i = 0; i < customData.GetLength(0); ++i)
            {
                customDictionary.Add(customData[i], i);
            }
            watch.Stop();
            Console.WriteLine("  Fill CustomKey Dictionary Elapsed Time: " + ((double)watch.ElapsedTicks / Stopwatch.Frequency * 1000).ToString());
            
            
            GC.Collect();
            Console.WriteLine("  Search CustomKey Dictionary");
            watch.Start();
            for (int i = 0; i < customData.Length; ++i)
            {

                int result = customDictionary[customData[i]];
                if (result != i)
                    throw new InvalidOperationException();

            }
            watch.Stop();
            Console.WriteLine("  Search CustomKey  Dictionary  Elapsed Time: " + ((double)watch.ElapsedTicks / Stopwatch.Frequency * 1000).ToString());
            customDictionary = null;

            GC.Collect();
            Console.WriteLine();
            Console.WriteLine(" Fill CustomKey with Comparer Dictionary");
            watch.Reset();
            watch.Start();
            for (int i = 0; i < customData.GetLength(0); ++i)
            {
                customDictionaryWithComparer.Add(customData[i], i);
            }
            watch.Stop();
            Console.WriteLine("  Fill CustomKey with Comparer Dictionary Elapsed Time: " + ((double)watch.ElapsedTicks / Stopwatch.Frequency * 1000).ToString());


            GC.Collect();
            Console.WriteLine("  Search CustomKey with Comparer Dictionary");
            watch.Start();
            for (int i = 0; i < customData.Length; ++i)
            {

                int result = customDictionaryWithComparer[customData[i]];
                if (result != i)
                    throw new InvalidOperationException();

            }
            watch.Stop();
            Console.WriteLine("  Search CustomKey with Comparer Dictionary  Elapsed Time: " + ((double)watch.ElapsedTicks / Stopwatch.Frequency * 1000).ToString());
            customDictionaryWithComparer = null;

            Console.WriteLine();
            Console.WriteLine("Tests Finished, press any key to stop...");
            Console.ReadKey();
        }


        static void InitData(int dataSize)
        {
            stringData = new string[dataSize];
            stringOnBeginData = new string[dataSize];
            stringOnEndData = new string[dataSize];
            intData = new int[dataSize];
            guidData = new Guid[dataSize];
            byteData = new byte[dataSize][];
            customData = new CustomKey[dataSize];
            string onBeginGuid = Guid.NewGuid().ToString();
            string onEndGuid = Guid.NewGuid().ToString();

            for (int i = 0; i < dataSize; ++i)
            {
                stringData[i] = Guid.NewGuid().ToString();
                stringOnBeginData[i] = i.ToString() + "-" + onBeginGuid;
                stringOnEndData[i] = onEndGuid + "-" + i.ToString();
                intData[i] = i * 3;
                guidData[i] = Guid.NewGuid();
                byteData[i] = guidData[i].ToByteArray();
                customData[i] = new CustomKey(guidData[i], i);
            }

            GC.Collect();
            GC.Collect();
        }
    }
}
